home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Arsenal Files 8
/
The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO
/
prg_casm
/
snipview.zip
/
SNIPVIEW.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-16
|
45KB
|
1,293 lines
/*
SnipView SNIPPETS.NDX-compatible browser contest entry
Written by Tom Torfs (2:292/516@fidonet.org)
Donated to the public domain
Date written: 12-Aug-1996
Last update: 16-Sep-1996
Target operating systems: every operating system VidMgr supports
currently: * 16-bit and 32-bit MS-DOS
* 16-bit and 32-bit OS/2
* 32-bit Windows 95/NT
Tested compilers: Watcom C++ 10.6, Borland C++ 3.0
Uses: Andrew Clarke's excellent public domain VidMgr package
General notes:
* SnipView is strictly ANSI C and should compile without
problems on all ANSI-compliant compilers; the only
OS-specific part of it is VidMgr, so Snipview will
compile and run on all operating systems as long as
VidMgr-compatible functions are provided
* for DOS 16-bit it is recommended to compile using
the compact or large memory model, to avoid
"not enough memory" errors
* limits for sections/groups/files/browser/notes are
easily expandable by changing the LIMITS array, in
case the snippets ever become really huge
of course they can be reduced also, for systems low on
memory (I've set the default limits a lot higher than
the current requirements)
* large files that don't fit in memory and/or that exceed
the number of lines in the LIMITS array, are truncated
* SnipView works independantly of the screen size (80x25,
80x50, 40x25, ...). The screen will always be fully used.
(note that a minimum width of 80 characters and a
minimum height of 25 lines is highly recommended)
Design notes:
* both window settings (coordinates, colors etc) and window
contents of all windows are kept in an array of WINDOW_INFO
structures (see comments accompanying struct definition for
more details on the implementation)
* the file window depends on the group window and the group
window in turn depends on the section window; check out the
BuildDependancies() function for more details
* each extended description line is stored as a separate item
with an index to the item it belongs to; this makes the rest
of the implementation (esp. the scrolling routines) much simpler
* hotkeys are available to jump immediately to a certain window,
Enter enters a window one level deeper, Esc exits to the
previous level window, and at all times Alt-X quits the program
(all these keys are visible on a help bar on the bottom line)
* all windows scroll if the information doesn't fit on one
screen, both horizontally and vertically, using the regular
cursor key controls (arrow keys, pgup/pgdn, home/end)
* searching for a keyword in all the snippets files is possible,
with case sensitivity and whole word search being selectable
Naming conventions:
* typedefs are lowercase if they define a simple data type
(bool, byte, word, ...), uppercase if they define a complex
data type (structs etc.)
* macros, enums, structs and constants are all uppercase,
distinct parts of compound names are separated by underscores
* functions are mixed case: the first letter of each distinct
part is uppercase, the rest lowercase (including first letter)
* global & static variables are mixed case, but the first letter
is always lowercase
* local variables are all lowercase
(of course these apply only to my own code, not to that of VidMgr
or the standard library)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "vidmgr.h"
#ifdef DOS
/* operating system id from Vidmgr
manipulated by FindNext() to avoid sluggish searching
under a multitasker */
extern int opsys_id;
#endif
typedef char bool;
#ifdef FALSE
#undef FALSE
#endif
#ifdef TRUE
#undef TRUE
#endif
enum {FALSE,TRUE};
enum {ENTER=0x000D,ESC=0x001B,BACKSPACE=0x0008,DELETE=0x5300,
ALTX=0x2D00,F1=0x3B00,F2=0x3C00,F3=0x3D00,F4=0x3E00,
UP=0x4800,DOWN=0x5000,LEFT=0x4B00,RIGHT=0x4D00,
PGUP=0x4900,PGDN=0x5100,HOME=0x4700,END=0x4F00};
enum {NOWINDOW=-1,
SECTIONWINDOW,GROUPWINDOW,FILEWINDOW,BROWSEWINDOW,NOTEWINDOW,
WINDOWS};
static const short LIMITS[WINDOWS]
= {64,256,2048,4096,256};
static char DEFAULT_INDEXFILE[]
= "SNIPPETS.NDX";
static char FILE_NOT_FOUND[]
= "*** File not found ***";
static char FILE_TRUNCATED[]
= "*** File truncated ***";
#define BUFLEN 256
static char buffer[BUFLEN];
static short screenCols;
static short screenRows;
static short fileNr = -1;
static char fileName[13];
static char findString[80];
static short findStringLength = 0;
static bool findCase = TRUE;
static bool findWord = FALSE;
static short findFileNr = -1;
static short findLineNr = 0;
static short findColNr = 0;
static bool found = FALSE;
static int activeWindow;
struct WINDOW_INFO
{
char x1,y1,x2,y2; /* coordinates */
char attr; /* normal text attribute */
char attrhigh; /* highlighted text attribute */
char attrselected; /* selected text attribute */
const char *title; /* window title */
short cols; /* columns of text */
short rows; /* rows of text */
short column; /* leftmost column on screen (0-based) */
bool scrollbar; /* use scroll bar */
bool exclusive; /* is window exclusive (fullscreen) */
short items; /* number of items in list */
short activeitem; /* currently selected item */
short firstitem; /* first item on screen */
short startitem; /* current first item in list (inclusive) */
short enditem; /* current last item in list (exclusive) */
char **list; /* list of pointers to items */
short dependingwindow; /* window that depends on this one */
short *dependingfirst; /* first item in depending window */
bool allowextdescriptions; /* extended descriptions allowed ? */
short *descriptionowner; /* ext. description owner or -1 for none */
};
struct WINDOW_INFO window[WINDOWS] =
{
{1,1,80,7,vm_mkcolor(BLACK,GREEN),vm_mkcolor(BLACK,LIGHTGRAY),vm_mkcolor(WHITE,GREEN),
"Sections",78,5,0,TRUE,FALSE,0,0,0,0,0,NULL,GROUPWINDOW,NULL,FALSE,NULL},
{1,8,80,14,vm_mkcolor(BLACK,CYAN),vm_mkcolor(BLACK,LIGHTGRAY),vm_mkcolor(WHITE,CYAN),
"Groups",78,5,0,TRUE,FALSE,0,0,0,0,0,NULL,FILEWINDOW,NULL,FALSE,NULL},
{1,15,80,24,vm_mkcolor(LIGHTGRAY,BLUE),vm_mkcolor(BLACK,LIGHTGRAY),vm_mkcolor(WHITE,BLUE),
"Files",78,8,0,TRUE,FALSE,0,0,0,0,0,NULL,NOWINDOW,NULL,TRUE,NULL},
{1,1,80,24,vm_mkcolor(LIGHTGRAY,BLUE),vm_mkcolor(BLACK,LIGHTGRAY),vm_mkcolor(WHITE,BLUE),
fileName,78,22,0,FALSE,TRUE,0,0,0,0,0,NULL,NOWINDOW,NULL,FALSE,NULL},
{1,1,80,24,vm_mkcolor(LIGHTGRAY,BLUE),vm_mkcolor(BLACK,LIGHTGRAY),vm_mkcolor(WHITE,BLUE),
"Notes",78,22,0,FALSE,TRUE,0,0,0,0,0,NULL,NOWINDOW,NULL,FALSE,NULL}
};
/* edit a string, returns length */
int EditString(int x, int y, char attr, char *s, int maxlen)
{
int len;
int pos;
int key;
bool done = FALSE;
bool origstring = TRUE;
len = strlen(s);
pos = len;
do
{
vm_xprintf(x,y,attr,"%-*s",maxlen,s);
vm_gotoxy(x+pos,y);
vm_setcursorstyle(CURSORNORM);
key = vm_getch();
vm_setcursorstyle(CURSORHIDE);
switch(key)
{
case ENTER:
done = TRUE;
break;
case ESC:
len = 0;
s[0] = '\0';
pos = 0;
break;
case BACKSPACE:
if (pos>0)
{
pos--;
memmove(s+pos,s+pos+1,strlen(s+pos+1)+1);
len--;
}
break;
case DELETE:
if (pos<len)
{
memmove(s+pos,s+pos+1,strlen(s+pos+1)+1);
len--;
}
break;
case LEFT:
if (pos>0)
pos--;
break;
case RIGHT:
if (pos<len)
pos++;
break;
case HOME:
pos = 0;
break;
case END:
pos = len;
break;
default:
if (key>=32 && key<=254 && key!=127)
{
if (origstring)
{
pos = 0;
len = 0;
}
if (len<maxlen)
{
if (pos<len)
memmove(s+pos+1,s+pos,strlen(s+pos)+1);
s[pos] = key;
pos++;
len++;
}
s[len] = '\0';
}
break;
}
origstring = FALSE;
}
while (!done);
return len;
}
/* ask for a yes/no answer */
bool AskYesNo(int x, int y, char attr, char *s, bool def)
{
bool yesno;
bool done = FALSE;
int key;
vm_xprintf(x,y,attr,"%s ? (%c/%c)",s,def?'Y':'y',def?'n':'N');
vm_gotoxy(x+strlen(s)+9,y);
do
{
vm_setcursorstyle(CURSORNORM);
key = vm_getch();
vm_setcursorstyle(CURSORHIDE);
switch(key)
{
case ENTER:
yesno = def;
done = TRUE;
break;
case 'Y':
case 'y':
yesno = TRUE;
done = TRUE;
break;
case 'N':
case 'n':
yesno = FALSE;
done = TRUE;
break;
}
}
while (!done);
return yesno;
}
/* allocate memory and check for errors */
void MemAlloc(void **ptr, size_t size)
{
*ptr = malloc(size);
if (*ptr==NULL)
{
printf("Error: not enough memory\n");
exit(EXIT_FAILURE);
}
}
/* read a single line from a file
and strip off the newline from the end
returns lenght of string or EOF if end-of-file */
int ReadLineEof(char *buf, int maxlen, FILE *fp)
{
int length;
fgets(buf,maxlen,fp);
if (feof(fp))
return EOF;
/* cut off newline */
length = strlen(buf)-1;
buf[length] = '\0';
return length;
}
/* read a single line from a file, handle end-of-file error,
and strip off the newline from the end */
int ReadLine(char *buf, int maxlen, FILE *fp)
{
int length;
length = ReadLineEof(buf,maxlen,fp);
if (length==EOF)
{
printf("Error: unexpected end of file\n");
exit(EXIT_FAILURE);
}
return length;
}
/* read & interpret a SNIPPETS.NDX-compatible indexfile */
void ReadIndexFile(const char *indexname)
{
FILE *ndx;
int length;
int count;
bool done;
short lastfile = 0;
/* allocate memory */
for (count=0; count<WINDOWS; count++)
{
MemAlloc((void **)&window[count].list,LIMITS[count]*sizeof(char *));
if (window[count].dependingwindow!=NOWINDOW)
MemAlloc((void **)&window[count].dependingfirst,LIMITS[count]*sizeof(short));
if (window[count].allowextdescriptions)
MemAlloc((void **)&window[count].descriptionowner,LIMITS[count]*sizeof(short));
}
ndx = fopen(indexname,"r");
if (ndx==NULL)
{
printf("Error: can't read index file %s\n",indexname);
exit(EXIT_FAILURE);
}
/* read date information & notes */
length = ReadLine(buffer,BUFLEN,ndx);
if (memcmp(buffer,"| +++",5)==0)
{
length -= 5;
memmove(buffer,buffer+5,length+1);
MemAlloc((void **)&window[NOTEWINDOW].list[window[NOTEWINDOW].items],length+1);
strcpy(window[NOTEWINDOW].list[window[NOTEWINDOW].items],buffer);
window[NOTEWINDOW].items++;
}
length = ReadLine(buffer,BUFLEN,ndx);
if (memcmp(buffer,"| ~~~",5)==0)
{
length -= 5;
memmove(buffer,buffer+5,length+1);
MemAlloc((void **)&window[NOTEWINDOW].list[window[NOTEWINDOW].items],length+1);
strcpy(window[NOTEWINDOW].list[window[NOTEWINDOW].items],buffer);
window[NOTEWINDOW].items++;
MemAlloc((void **)&window[NOTEWINDOW].list[window[NOTEWINDOW].items],1);
/* add blank line to separate from notes */
window[NOTEWINDOW].list[window[NOTEWINDOW].items][0] = '\0';
window[NOTEWINDOW].items++;
}
do
length = ReadLine(buffer,BUFLEN,ndx);
while (memicmp(buffer,"|NOTES:",7)!=0);
do
{
if (window[NOTEWINDOW].items<LIMITS[NOTEWINDOW])
{
MemAlloc((void **)&window[NOTEWINDOW].list[window[NOTEWINDOW].items],length);
strcpy(window[NOTEWINDOW].list[window[NOTEWINDOW].items],buffer+1);
window[NOTEWINDOW].items++;
}
length = ReadLine(buffer,BUFLEN,ndx);
}
while (buffer[0]=='|');
/* section loop */
done = FALSE;
do
{
/* read section description */
while (length<2 || buffer[1]!='*')
length = ReadLine(buffer,BUFLEN,ndx);
window[SECTIONWINDOW].list[window[SECTIONWINDOW].items] = NULL;
do
{
while (length>0 && (ispunct(buffer[0])||isspace(buffer[0])))
memmove(buffer,buffer+1,length--);
while (length>0 && (ispunct(buffer[length-1])||isspace(buffer[length-1]))
&& buffer[length-1]!=')')
buffer[--length] = '\0';
if (length>0 && window[SECTIONWINDOW].list[window[SECTIONWINDOW].items]==NULL)
{
MemAlloc((void **)&window[SECTIONWINDOW].list[window[SECTIONWINDOW].items],length+1);
strcpy(window[SECTIONWINDOW].list[window[SECTIONWINDOW].items],buffer);
}
length = ReadLine(buffer,BUFLEN,ndx);
}
while (length<2 || buffer[1]!='*');
window[SECTIONWINDOW].dependingfirst[window[SECTIONWINDOW].items] = window[GROUPWINDOW].items;
/* group loop */
do
{
/* read group description */
while (length<2 || buffer[1]!='=')
length = ReadLine(buffer,BUFLEN,ndx);
window[GROUPWINDOW].list[window[GROUPWINDOW].items] = NULL;
do
{
while (length>0 && (ispunct(buffer[0])||isspace(buffer[0])))
memmove(buffer,buffer+1,length--);
while (length>0 && (ispunct(buffer[length-1])||isspace(buffer[length-1]))
&& buffer[length-1]!=')')
buffer[--length] = '\0';
if (length>0 && window[GROUPWINDOW].list[window[GROUPWINDOW].items]==NULL)
{
MemAlloc((void **)&window[GROUPWINDOW].list[window[GROUPWINDOW].items],length+1);
strcpy(window[GROUPWINDOW].list[window[GROUPWINDOW].items],buffer);
}
length = ReadLine(buffer,BUFLEN,ndx);
}
while (length<2 || buffer[1]!='=');
/* final group with deleted files ? if so, skip it */
if (memicmp(window[GROUPWINDOW].list[window[GROUPWINDOW].items],"Files deleted",13)==0)
{
free(window[GROUPWINDOW].list[window[GROUPWINDOW].items]);
do
{
length = ReadLineEof(buffer,BUFLEN,ndx);
if (length==EOF)
done = TRUE;
}
while (!done && (length<2 || (buffer[1]!='=' && buffer[1]!='*')));
break;
}
window[GROUPWINDOW].dependingfirst[window[GROUPWINDOW].items] = window[FILEWINDOW].items;
/* files loop */
do
{
length = ReadLineEof(buffer,BUFLEN,ndx);
if (length==EOF)
done = TRUE;
else if (length>3
&& (buffer[0]=='*' || buffer[0]=='+'
|| buffer[0]=='-' || buffer[0]==' '))
{
MemAlloc((void **)&window[FILEWINDOW].list[window[FILEWINDOW].items],length+1);
strcpy(window[FILEWINDOW].list[window[FILEWINDOW].items],buffer);
if (buffer[0]==' ' && buffer[2]==' ')
window[FILEWINDOW].descriptionowner[window[FILEWINDOW].items]
= lastfile;
else
{
window[FILEWINDOW].descriptionowner[window[FILEWINDOW].items]
= -1;
lastfile = window[FILEWINDOW].items;
}
window[FILEWINDOW].items++;
if (window[FILEWINDOW].items==LIMITS[FILEWINDOW])
done = TRUE;
}
}
while (!done && (length<2 || (buffer[1]!='=' && buffer[1]!='*')));
window[GROUPWINDOW].items++;
if (window[GROUPWINDOW].items==LIMITS[GROUPWINDOW])
done = TRUE;
}
while (!done && buffer[1]!='*');
window[SECTIONWINDOW].items++;
if (window[SECTIONWINDOW].items==LIMITS[SECTIONWINDOW])
done = TRUE;
}
while (!done);
fclose(ndx);
}
/* load a file in the browse window
returns TRUE if file was wholly or partially loaded,
FALSE if not */
bool LoadFile(short filenr)
{
FILE *fp;
int count;
int length;
bool done;
bool status;
/* free a possible previous file */
if (window[BROWSEWINDOW].items>0)
{
for (count=window[BROWSEWINDOW].items-1; count>=0; count--)
{
if (window[BROWSEWINDOW].list[count]!=FILE_NOT_FOUND
&& window[BROWSEWINDOW].list[count]!=FILE_TRUNCATED)
free(window[BROWSEWINDOW].list[count]);
}
}
window[BROWSEWINDOW].items = 0;
fileNr = filenr;
strncpy(fileName,window[FILEWINDOW].list[filenr]+2,12);
fileName[12] = '\0';
strtok(fileName," ");
fp = fopen(fileName,"r");
if (fp==NULL)
{
window[BROWSEWINDOW].list[0] = FILE_NOT_FOUND;
window[BROWSEWINDOW].items = 1;
status = FALSE;
}
else
{
done = FALSE;
do
{
length = ReadLineEof(buffer,BUFLEN,fp);
if (length==-1)
done = TRUE;
else
{
window[BROWSEWINDOW].list[window[BROWSEWINDOW].items] = malloc(length+1);
if (window[BROWSEWINDOW].list[window[BROWSEWINDOW].items]==NULL)
{
window[BROWSEWINDOW].list[window[BROWSEWINDOW].items] = FILE_TRUNCATED;
done = TRUE;
}
else
strcpy(window[BROWSEWINDOW].list[window[BROWSEWINDOW].items],buffer);
window[BROWSEWINDOW].items++;
if (window[BROWSEWINDOW].items==LIMITS[BROWSEWINDOW]-1)
{
window[BROWSEWINDOW].list[window[BROWSEWINDOW].items] = FILE_TRUNCATED;
window[BROWSEWINDOW].items++;
done = TRUE;
}
}
}
while (!done);
fclose(fp);
status = TRUE;
}
return status;
}
/* rebuild all dependancies of a window
recursively calls itself for deeper levels of dependancy */
void BuildDependancies(int windownr)
{
int depwin;
depwin = window[windownr].dependingwindow;
if (depwin==NOWINDOW)
return;
window[depwin].startitem = window[windownr].dependingfirst[window[windownr].activeitem];
if (window[windownr].activeitem<window[windownr].items-1)
window[depwin].enditem = window[windownr].dependingfirst[window[windownr].activeitem+1];
else
window[depwin].enditem = window[depwin].items;
if (window[depwin].firstitem<window[depwin].startitem ||
window[depwin].firstitem+window[depwin].rows>window[depwin].enditem)
{
window[depwin].firstitem = window[depwin].startitem;
window[depwin].activeitem = window[depwin].firstitem;
}
BuildDependancies(depwin);
}
/* does window1 depend on window2 ?
recursively calls itself for deeper levels of dependancy */
bool WindowDepends(int window1, int window2)
{
int depwin;
depwin = window[window2].dependingwindow;
if (depwin==NOWINDOW)
return FALSE;
if (depwin==window1)
return TRUE;
return WindowDepends(window1,depwin);
}
/* initialize windows after reading */
void InitWindows(void)
{
int count;
/* initialize startitem and enditem for all windows */
for (count=0; count<WINDOWS; count++)
{
window[count].startitem = 0;
window[count].enditem = window[count].items;
}
activeWindow = SECTIONWINDOW;
}
/* redraw a window, if it is on screen */
void DrawWindow(int windownr)
{
int x,y;
int nr;
char a;
bool active;
int titlestartx,titleendx;
active = (windownr==activeWindow);
if (!active && window[windownr].exclusive)
return;
if (!active && window[activeWindow].exclusive)
return;
/* display title */
titlestartx = window[windownr].x1
+ (window[windownr].cols-strlen(window[windownr].title)-2)/2
- 1;
titleendx = titlestartx + strlen(window[windownr].title) + 1;
vm_xprintf(titlestartx,window[windownr].y1,window[windownr].attr,
" %s ",window[windownr].title);
/* draw borders */
if (active)
{
for (x=window[windownr].x1+1; x<window[windownr].x2; x++)
{
if (x<titlestartx || x>titleendx)
vm_xputch(x,window[windownr].y1,window[windownr].attr,'═');
vm_xputch(x,window[windownr].y2,window[windownr].attr,'═');
}
for (y=window[windownr].y1+1; y<window[windownr].y2; y++)
{
vm_xputch(window[windownr].x1,y,window[windownr].attr,'║');
vm_xputch(window[windownr].x2,y,window[windownr].attr,'║');
}
}
else
{
for (x=window[windownr].x1+1; x<window[windownr].x2; x++)
{
if (x<titlestartx || x>titleendx)
vm_xputch(x,window[windownr].y1,window[windownr].attr,'─');
vm_xputch(x,window[windownr].y2,window[windownr].attr,'─');
}
for (y=window[windownr].y1+1; y<window[windownr].y2; y++)
{
vm_xputch(window[windownr].x1,y,window[windownr].attr,'│');
vm_xputch(window[windownr].x2,y,window[windownr].attr,'│');
}
}
/* draw corners */
if (active)
{
vm_xputch(window[windownr].x1,window[windownr].y1,window[windownr].attr,'╔');
vm_xputch(window[windownr].x2,window[windownr].y1,window[windownr].attr,'╗');
vm_xputch(window[windownr].x1,window[windownr].y2,window[windownr].attr,'╚');
vm_xputch(window[windownr].x2,window[windownr].y2,window[windownr].attr,'╝');
}
else
{
vm_xputch(window[windownr].x1,window[windownr].y1,window[windownr].attr,'┌');
vm_xputch(window[windownr].x2,window[windownr].y1,window[windownr].attr,'┐');
vm_xputch(window[windownr].x1,window[windownr].y2,window[windownr].attr,'└');
vm_xputch(window[windownr].x2,window[windownr].y2,window[windownr].attr,'┘');
}
/* display the contents */
nr = window[windownr].firstitem;
for (y=window[windownr].y1+1; y<=window[windownr].y2-1; y++,nr++)
{
if (active && window[windownr].scrollbar
&& (nr==window[windownr].activeitem
|| (window[windownr].allowextdescriptions
&& window[windownr].descriptionowner[nr]==window[windownr].activeitem)))
a = window[windownr].attrhigh;
else if (window[windownr].scrollbar && WindowDepends(activeWindow,windownr)
&& (nr==window[windownr].activeitem
|| (window[windownr].allowextdescriptions
&& window[windownr].descriptionowner[nr]==window[windownr].activeitem)))
a = window[windownr].attrselected;
else
a = window[windownr].attr;
if (nr>=window[windownr].startitem && nr<window[windownr].enditem
&& strlen(window[windownr].list[nr])>window[windownr].column)
{
sprintf(buffer," %-*s",window[windownr].cols-1,
window[windownr].list[nr]+window[windownr].column);
if (strlen(buffer)>window[windownr].cols)
buffer[window[windownr].cols] = '\0';
vm_xprintf(window[windownr].x1+1,y,a,"%s",buffer);
if (windownr==BROWSEWINDOW && found
&& findFileNr==fileNr && findLineNr==nr)
vm_paintbox(window[windownr].x1+2+findColNr,y,
window[windownr].x1+2+findColNr+findStringLength-1,y,
window[windownr].attrselected);
}
else
vm_paintclearbox(window[windownr].x1+1,y,window[windownr].x2-1,y,a);
}
}
/* redraw all windows currently on screen */
void DrawWindows(void)
{
int count;
for (count=0; count<WINDOWS; count++)
DrawWindow(count);
}
/* draw the status bar */
void DrawStatusBar(void)
{
vm_paintclearline(screenRows,vm_mkcolor(BLACK,LIGHTGRAY));
vm_xprintf(2, screenRows, vm_mkcolor(YELLOW,LIGHTGRAY), "SnipView");
if (screenCols>=23)
{
vm_xprintf(12, screenRows, vm_mkcolor(RED,LIGHTGRAY), "Enter");
vm_xprintf(17, screenRows, vm_mkcolor(BLACK,LIGHTGRAY), "-Select");
}
if (screenCols>=32)
{
vm_xprintf(25, screenRows, vm_mkcolor(RED,LIGHTGRAY), "ESC");
vm_xprintf(28, screenRows, vm_mkcolor(BLACK,LIGHTGRAY), "-Prev");
}
if (screenCols>=46)
{
vm_xprintf(34, screenRows, vm_mkcolor(RED,LIGHTGRAY), "F1..F3");
vm_xprintf(40, screenRows, vm_mkcolor(BLACK,LIGHTGRAY), "-Window");
}
if (screenCols>=55)
{
vm_xprintf(48, screenRows, vm_mkcolor(RED,LIGHTGRAY), "F4");
vm_xprintf(50, screenRows, vm_mkcolor(BLACK,LIGHTGRAY), "-Notes");
}
if (screenCols>=62)
{
vm_xprintf(57, screenRows, vm_mkcolor(RED,LIGHTGRAY), "F");
vm_xprintf(58, screenRows, vm_mkcolor(BLACK,LIGHTGRAY), "-Find");
}
if (screenCols>=69)
{
vm_xprintf(64, screenRows, vm_mkcolor(RED,LIGHTGRAY), "N");
vm_xprintf(65, screenRows, vm_mkcolor(BLACK,LIGHTGRAY), "-Next");
}
if (screenCols>=79)
{
vm_xprintf(71, screenRows, vm_mkcolor(RED,LIGHTGRAY), "AltX");
vm_xprintf(75, screenRows, vm_mkcolor(BLACK,LIGHTGRAY), "-Quit");
}
}
/* prompt for find parameters */
void SelectFind(void)
{
vm_xprintf(2,screenRows,vm_mkcolor(BLACK,LIGHTGRAY),"Find: ");
findStringLength = EditString(8,screenRows,vm_mkcolor(BLACK,LIGHTGRAY),
findString,72);
if (findStringLength>0)
{
vm_paintclearline(screenRows,vm_mkcolor(BLACK,LIGHTGRAY));
findCase = AskYesNo(2,screenRows,vm_mkcolor(BLACK,LIGHTGRAY),
"Case sensitive search",findCase);
vm_paintclearline(screenRows,vm_mkcolor(BLACK,LIGHTGRAY));
findWord = AskYesNo(2,screenRows,vm_mkcolor(BLACK,LIGHTGRAY),
"Whole word search",findWord);
}
DrawStatusBar();
if (activeWindow==BROWSEWINDOW)
{
findFileNr = fileNr;
findLineNr = window[activeWindow].firstitem;
findColNr = -1;
}
else
findFileNr = -1;
}
/* find next occurence of string */
void FindNext(void)
{
bool done = FALSE;
short filenr;
short oldfilenr;
char *s;
int key;
#ifdef DOS
int oldid;
#endif
vm_paintclearline(screenRows,vm_mkcolor(BLACK,LIGHTGRAY));
vm_xprintf(2,screenRows,vm_mkcolor(BLACK|BLINK,LIGHTGRAY),
"Searching...");
vm_xprintf(53,screenRows,vm_mkcolor(BLACK,LIGHTGRAY),
"(press ESC to abort search)");
#ifdef DOS
/* disable vm_kbhit() giving away timeslices,
necessary to avoid sluggish searching */
oldid = opsys_id;
opsys_id = -1;
#endif
oldfilenr = fileNr;
if (findFileNr!=-1 && fileNr!=findFileNr)
LoadFile(findFileNr);
findColNr++;
found = FALSE;
do
{
if (findFileNr==-1 || findLineNr==window[BROWSEWINDOW].items)
{
do
{
findFileNr++;
if (findFileNr==window[FILEWINDOW].items)
{
findFileNr = -1;
done = TRUE;
}
}
while (!done && !LoadFile(findFileNr));
vm_xprintf(15,screenRows,vm_mkcolor(BLACK,LIGHTGRAY),
"%-12s",fileName);
findLineNr = 0;
findColNr = 0;
}
s = window[BROWSEWINDOW].list[findLineNr]+findColNr;
while (!done && *s!='\0')
{
if (((findCase && memcmp(s,findString,findStringLength)==0)
|| (!findCase && memicmp(s,findString,findStringLength)==0))
&& (!findWord
|| ((findColNr==0 || (!isalnum(s[-1]) && s[-1]!='_'))
&& (!isalnum(s[findStringLength]) && s[findStringLength]!='_'))))
{
found = TRUE;
done = TRUE;
}
else
{
findColNr++;
s++;
}
}
if (!done)
{
findLineNr++;
findColNr = 0;
}
if (vm_kbhit())
{
key = vm_getch();
if (key==ESC)
done = TRUE;
}
}
while (!done);
DrawStatusBar();
if (!found && activeWindow==BROWSEWINDOW && fileNr!=oldfilenr)
LoadFile(oldfilenr);
#ifdef DOS
/* restore VidMgr's timeslicing support */
opsys_id = oldid;
#endif
}
/* browse through the windows interactively */
void BrowseWindows(void)
{
bool done = FALSE;
short prevwinnotes;
short prevwinbrowser;
short count;
short filenr;
do
{
BuildDependancies(activeWindow);
DrawWindows();
switch(vm_getch())
{
case UP:
if (window[activeWindow].scrollbar)
{
if (window[activeWindow].activeitem>window[activeWindow].startitem)
{
do
{
window[activeWindow].activeitem--;
if (window[activeWindow].activeitem<window[activeWindow].firstitem)
window[activeWindow].firstitem--;
}
while (window[activeWindow].allowextdescriptions
&& window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
&& window[activeWindow].activeitem>window[activeWindow].startitem);
if (window[activeWindow].activeitem==window[activeWindow].startitem)
{
while (window[activeWindow].allowextdescriptions
&& window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
&& window[activeWindow].activeitem<window[activeWindow].enditem-1)
{
window[activeWindow].activeitem++;
if (window[activeWindow].activeitem>=window[activeWindow].firstitem
+ window[activeWindow].rows)
window[activeWindow].firstitem++;
}
}
}
}
else
{
if (window[activeWindow].firstitem>window[activeWindow].startitem)
window[activeWindow].firstitem--;
}
break;
case DOWN:
if (window[activeWindow].scrollbar)
{
if (window[activeWindow].activeitem<window[activeWindow].enditem-1)
{
do
{
window[activeWindow].activeitem++;
if (window[activeWindow].activeitem>=window[activeWindow].firstitem
+ window[activeWindow].rows)
window[activeWindow].firstitem++;
}
while (window[activeWindow].allowextdescriptions
&& window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
&& window[activeWindow].activeitem<window[activeWindow].enditem-1);
if (window[activeWindow].activeitem==window[activeWindow].enditem-1)
{
while (window[activeWindow].allowextdescriptions
&& window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
&& window[activeWindow].activeitem>window[activeWindow].startitem)
{
window[activeWindow].activeitem--;
if (window[activeWindow].activeitem<window[activeWindow].firstitem)
window[activeWindow].firstitem--;
}
}
}
}
else
{
if (window[activeWindow].firstitem+window[activeWindow].rows
<window[activeWindow].enditem)
window[activeWindow].firstitem++;
}
break;
case LEFT:
if (window[activeWindow].column>0)
{
window[activeWindow].column -= 8;
if (window[activeWindow].column<0)
window[activeWindow].column = 0;
}
break;
case RIGHT:
if (window[activeWindow].column<BUFLEN-window[activeWindow].cols)
{
window[activeWindow].column += 8;
if (window[activeWindow].column>BUFLEN-window[activeWindow].cols)
window[activeWindow].column = BUFLEN-window[activeWindow].cols;
}
break;
case PGUP:
if (window[activeWindow].firstitem>window[activeWindow].startitem
|| (window[activeWindow].scrollbar
&& window[activeWindow].activeitem>window[activeWindow].startitem))
{
window[activeWindow].firstitem -= window[activeWindow].rows;
if (window[activeWindow].firstitem<window[activeWindow].startitem)
window[activeWindow].firstitem = window[activeWindow].startitem;
if (window[activeWindow].scrollbar)
{
window[activeWindow].activeitem -= window[activeWindow].rows;
if (window[activeWindow].activeitem<window[activeWindow].startitem)
window[activeWindow].activeitem = window[activeWindow].startitem;
while (window[activeWindow].allowextdescriptions
&& window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
&& window[activeWindow].activeitem<window[activeWindow].enditem-1)
{
window[activeWindow].activeitem++;
if (window[activeWindow].firstitem+window[activeWindow].rows
<window[activeWindow].enditem)
window[activeWindow].firstitem++;
}
}
}
break;
case PGDN:
if (window[activeWindow].firstitem+window[activeWindow].rows<window[activeWindow].enditem
|| (window[activeWindow].scrollbar
&& window[activeWindow].activeitem<window[activeWindow].enditem-1))
{
window[activeWindow].firstitem += window[activeWindow].rows;
if (window[activeWindow].firstitem+window[activeWindow].rows>window[activeWindow].enditem)
window[activeWindow].firstitem = window[activeWindow].enditem-window[activeWindow].rows;
if (window[activeWindow].firstitem<window[activeWindow].startitem)
window[activeWindow].firstitem = window[activeWindow].startitem;
if (window[activeWindow].scrollbar)
{
window[activeWindow].activeitem += window[activeWindow].rows;
if (window[activeWindow].activeitem>window[activeWindow].enditem-1)
window[activeWindow].activeitem = window[activeWindow].enditem-1;
while (window[activeWindow].allowextdescriptions
&& window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
&& window[activeWindow].activeitem>window[activeWindow].startitem)
{
window[activeWindow].activeitem--;
if (window[activeWindow].activeitem<window[activeWindow].firstitem)
window[activeWindow].firstitem--;
}
}
}
break;
case HOME:
if (window[activeWindow].firstitem>window[activeWindow].startitem
|| (window[activeWindow].scrollbar
&& window[activeWindow].activeitem>window[activeWindow].startitem))
{
window[activeWindow].firstitem = window[activeWindow].startitem;
if (window[activeWindow].scrollbar)
{
window[activeWindow].activeitem = window[activeWindow].startitem;
while (window[activeWindow].allowextdescriptions
&& window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
&& window[activeWindow].activeitem<window[activeWindow].enditem-1)
{
window[activeWindow].activeitem++;
if (window[activeWindow].firstitem+window[activeWindow].rows
<window[activeWindow].enditem)
window[activeWindow].firstitem++;
}
}
}
break;
case END:
if (window[activeWindow].firstitem+window[activeWindow].rows<window[activeWindow].enditem
|| (window[activeWindow].scrollbar
&& window[activeWindow].activeitem<window[activeWindow].enditem-1))
{
window[activeWindow].firstitem = window[activeWindow].enditem-window[activeWindow].rows;
if (window[activeWindow].firstitem<window[activeWindow].startitem)
window[activeWindow].firstitem = window[activeWindow].startitem;
if (window[activeWindow].scrollbar)
{
window[activeWindow].activeitem = window[activeWindow].enditem-1;
while (window[activeWindow].allowextdescriptions
&& window[activeWindow].descriptionowner[window[activeWindow].activeitem]!=-1
&& window[activeWindow].activeitem>window[activeWindow].startitem)
{
window[activeWindow].activeitem--;
if (window[activeWindow].activeitem<window[activeWindow].firstitem)
window[activeWindow].firstitem--;
}
}
}
break;
case F1:
window[activeWindow].column = 0;
activeWindow = SECTIONWINDOW;
break;
case F2:
window[activeWindow].column = 0;
activeWindow = GROUPWINDOW;
break;
case F3:
window[activeWindow].column = 0;
activeWindow = FILEWINDOW;
break;
case F4:
if (activeWindow!=NOTEWINDOW)
{
prevwinnotes = activeWindow;
window[activeWindow].column = 0;
activeWindow = NOTEWINDOW;
window[activeWindow].firstitem = 0;
}
break;
case ENTER:
if (window[activeWindow].dependingwindow!=NOWINDOW)
{
window[activeWindow].column = 0;
activeWindow = window[activeWindow].dependingwindow;
}
else if (activeWindow==FILEWINDOW)
{
window[activeWindow].column = 0;
filenr = window[FILEWINDOW].activeitem;
if (window[FILEWINDOW].descriptionowner[filenr]!=-1)
filenr = window[FILEWINDOW].descriptionowner[filenr];
LoadFile(filenr);
window[BROWSEWINDOW].startitem = 0;
window[BROWSEWINDOW].enditem = window[BROWSEWINDOW].items;
window[BROWSEWINDOW].firstitem = 0;
window[BROWSEWINDOW].column = 0;
prevwinbrowser = activeWindow;
activeWindow = BROWSEWINDOW;
}
break;
case ESC:
switch(activeWindow)
{
case GROUPWINDOW:
window[activeWindow].column = 0;
activeWindow = SECTIONWINDOW;
break;
case FILEWINDOW:
window[activeWindow].column = 0;
activeWindow = GROUPWINDOW;
break;
case BROWSEWINDOW:
window[activeWindow].column = 0;
activeWindow = prevwinbrowser;
break;
case NOTEWINDOW:
window[activeWindow].column = 0;
activeWindow = prevwinnotes;
break;
}
break;
case 'F':
case 'f':
window[activeWindow].column = 0;
SelectFind();
/* deliberate fallthrough */
case 'N':
case 'n':
if (findStringLength>0)
{
FindNext();
if (found)
{
window[BROWSEWINDOW].startitem = 0;
window[BROWSEWINDOW].enditem = window[BROWSEWINDOW].items;
window[BROWSEWINDOW].firstitem = 0;
window[BROWSEWINDOW].column = 0;
if (activeWindow!=BROWSEWINDOW)
prevwinbrowser = activeWindow;
activeWindow = BROWSEWINDOW;
window[activeWindow].firstitem = findLineNr
- window[activeWindow].rows/2;
if (window[activeWindow].firstitem<window[activeWindow].startitem)
window[activeWindow].firstitem = window[activeWindow].startitem;
}
}
break;
case ALTX:
done = TRUE;
break;
}
}
while (!done);
}
/* initialize vidmgr, clear screen, draw status bar & scale windows */
void InitScreen(void)
{
int count;
vm_init();
screenCols = vm_getscreenwidth();
screenRows = vm_getscreenheight();
vm_setcursorstyle(CURSORHIDE);
vm_setattr(vm_mkcolor(LIGHTGRAY,BLACK));
vm_clrscr();
DrawStatusBar();
for (count=0; count<WINDOWS; count++)
{
window[count].x1 = 1 + ((window[count].x1 - 1) * screenCols/80);
window[count].y1 = 1 + ((window[count].y1 - 1) * screenRows/25);
if (window[count].x2==80) /* always round up to edge of screen */
window[count].x2 = screenCols;
else
window[count].x2 = screenCols - ((80 - window[count].x2)
* screenCols/80);
if (window[count].y2==24) /* leave a line for the status bar */
window[count].y2 = screenRows - 1;
else
window[count].y2 = screenRows - ((25 - window[count].y2)
* screenRows/25);
window[count].cols = window[count].x2 - window[count].x1 - 1;
window[count].rows = window[count].y2 - window[count].y1 - 1;
}
}
/* deinitialize vidmgr & clear screen */
void DeInitScreen(void)
{
vm_setattr(LIGHTGRAY);
vm_clrscr();
vm_setcursorstyle(CURSORNORM);
vm_done();
}
int main(int argc, char *argv[])
{
char *indexfile;
if (argc>1)
{
if (argc>2 || strchr(argv[1],'?')!=NULL)
{
printf("SnipView snippets browser by Tom Torfs\n\n");
printf("Usage: SNIPVIEW [indexfile]\n\n");
printf("Default is %s.\n",DEFAULT_INDEXFILE);
return EXIT_FAILURE;
}
indexfile = argv[1];
}
else
indexfile = DEFAULT_INDEXFILE;
ReadIndexFile(indexfile);
InitWindows();
InitScreen();
BrowseWindows();
DeInitScreen();
return EXIT_SUCCESS;
}